import unittest
import world
import math

class WorldTest(unittest.TestCase):
    """Test case for the world.py module"""
    def setUp(self):
        self.world1 = world.World()
        self.world1.populate()
        self.empty_world = world.World()
        self.empty_world.populate(0, 0)
        self.default = world.DEF_TOWNS
    
    def test_populate(self):
        my_world = world.World()
        default = world.DEF_TOWNS
        
        self.assertEqual(my_world.get_width(), 0)
        self.assertEqual(my_world.get_height(), 0)
        
        
        #test deafult
        my_world.populate()
        self.assertEqual(my_world.get_width(), default)
        self.assertEqual(my_world.get_height(), default)
        self.assertTrue(test_world_dim(my_world, default, default))
        
        #test values
        neg = [-1, -5, -11, -65, -200]
        pos = [0, 1, 4, 8, 15, 100]
        
        #test negative x values produce error
        for i in neg:
            self.assertRaises(Exception, my_world.populate, i)
            for j in pos:
                self.assertRaises(
                    Exception, world.World.populate, my_world, i, j)
                
            for j in neg:
                self.assertRaises(
                    Exception, world.World.populate, my_world, i, j)
                
        #test negative y values produce default
        for i in neg:
            my_world.populate(height=i)
            self.assertTrue(test_world_dim(my_world, default, default))
            self.assertEqual(my_world.get_width(), default)
            self.assertEqual(my_world.get_height(), default)
        
        
        #test positive x values mirrored on default y values
        for i in pos:
            my_world.populate(i)
            
            self.assertTrue(test_world_dim(my_world, i, i))
            self.assertEqual(my_world.get_width(), i)
            self.assertEqual(my_world.get_height(), i)
            
            for j in neg:
                my_world.populate(i, j)
                self.assertTrue(test_world_dim(my_world, i, i))
                self.assertEqual(my_world.get_width(), i)
                self.assertEqual(my_world.get_height(), i)
            
                
        #test positive x and y yield x = width, y = height
        for i in pos:
            for j in pos:
                my_world.populate(i, j)
                self.assertTrue(test_world_dim(my_world, i, j))
                self.assertEqual(my_world.get_width(), i)
                if(i > 0):
                    self.assertEqual(my_world.get_height(), j)
                else:
                    self.assertEqual(my_world.get_height(), 0)
                    
    def test_get_town(self):
        w = self.world1
        for x in range(w.get_width()):
            for y in range(w.get_height()):
                self.assertFalse(w.get_town(x, y) == None)
        
        for x in range(w.get_width(), w.get_width() + 10):
            for y in range(w.get_height()):
                self.assertIsNone(w.get_town(x, y))
    
    def test_get_route(self):
        high = range(self.default, 2 * self.default)
        pos = range(self.default)
        neg = map(lambda x:-x, pos)
        neg.pop(0)
        all = [high, pos, neg]
        
        empty = self.empty_world
        full = self.world1
        
        #test values return no routes in empty world
        for srcx in all:
         for srcy in all:
          for destx in all:
           for desty in all:
            for sx in srcx:
             for sy in srcy:
              for dx in destx:
               for dy in desty:
                self.assertIsNone(empty.get_route(sx, sy, dx, dy))
         
        #test high values return no routes
        for srcy in all:
         for destx in all:
          for desty in all:
           for sx in high:
            for sy in srcy:
             for dx in destx:
              for dy in desty:
               self.assertIsNone(full.get_route(sx, sy, dx, dy))
        
        for srcx in all:
         for destx in all:
          for desty in all:
           for sx in srcx:
            for sy in high:
             for dx in destx:
              for dy in desty:
               self.assertIsNone(full.get_route(sx, sy, dx, dy))
        
        for srcx in all:
         for srcy in all:
          for desty in all:
           for sx in srcx:
            for sy in srcy:
             for dx in high:
              for dy in desty:
               self.assertIsNone(full.get_route(sx, sy, dx, dy))
        
        for srcx in all:
         for srcy in all:
          for destx in all:
           for sx in srcx:
            for sy in srcy:
             for dx in destx:
              for dy in high:
               self.assertIsNone(full.get_route(sx, sy, dx, dy))
        
        #test neg values return no routes
        for srcy in all:
         for destx in all:
          for desty in all:
           for sx in neg:
            for sy in srcy:
             for dx in destx:
              for dy in desty:
               self.assertIsNone(full.get_route(sx, sy, dx, dy))
        
        for srcx in all:
         for destx in all:
          for desty in all:
           for sx in srcx:
            for sy in neg:
             for dx in destx:
              for dy in desty:
               self.assertIsNone(full.get_route(sx, sy, dx, dy))
        
        for srcx in all:
         for srcy in all:
          for desty in all:
           for sx in srcx:
            for sy in srcy:
             for dx in neg:
              for dy in desty:
               self.assertIsNone(full.get_route(sx, sy, dx, dy))
        
        for srcx in all:
         for srcy in all:
          for destx in all:
           for sx in srcx:
            for sy in srcy:
             for dx in destx:
              for dy in neg:
               self.assertIsNone(full.get_route(sx, sy, dx, dy))
        
        #test valid values
        for sx in pos:
         for sy in pos:
          for dx in pos:
           for dy in pos:
            distance = math.fabs(sx - dx) + math.fabs(sy - dy)
            if(distance == 1):
                self.assertTrue(full.get_route(sx, sy, dx, dy))
            else:
                self.assertIsNone(full.get_route(sx, sy, dx, dy))
        
        #test negative values return no routes    
        
        
        
        
        
            
                

#################################
###### UTIL #####################
#################################

def test_world_dim(the_world, width, height):
    """
    returns true if the world has the given hieght and width
    """
    
    if len(the_world._towns) != width:
        print "Town width is '{0:d}' not expected width '{1:d}'".format(
                len(the_world._towns), width)
        return False
    
    east_width = width - 1
    if(east_width < 0):
        east_width = 0
    
    if len(the_world._e_routes) != east_width:
        print "East routes width is '{0:d}' not expected width '{1:d}'".format(
                len(the_world._e_routes), east_width)
        return False
    if len(the_world._s_routes) != width:
        print "South routes width '{0:d}' is not expected width '{1:d}'".format(
               len(the_world._s_routes), width)
        return False
    
    
    for x in range(width):
        if len(the_world._towns[x]) != height:
            print "Town height is '{0:d}' not expected height '{1:d}'".format(
                   len(the_world._towns[x]), height)
            return False
        if x > 0 and len(the_world._e_routes[x-1]) != height:
            print "East routes height is {0:d} not expected height '{1:d}'"\
                   .format(len(the_world._e_routes[x-1]), height)
            return False
        south_height = height - 1
        if(south_height < 0):
            south_height = 0
    
        if len(the_world._s_routes[x]) != south_height:
            print "South routes height '{0:d}' is not expected height '{1:d}'"\
                  .format(len(the_world._s_routes[x]), south_height)
            return False
    return True

   

if __name__ == '__main__':
    unittest.main()
    
def get_suite():
    return unittest.makeSuite(WorldTest)